#!/usr/bin/env python3
"""
ZOS IP客户端 - 完整修复版
与Fog IP服务器端完全兼容
修复重复确认窗口问题 - 合并IP和DNS修改
修改计算机名弹窗参照修改IP的方法
"""

#pip install requests
#pip install psutil
#pip install pillow
#pip install pystray

import sys
import os
import ctypes
import subprocess

def is_admin():
    """检查是否以管理员权限运行"""
    try:
        return ctypes.windll.shell32.IsUserAnAdmin()
    except:
        return False

def run_as_admin():
    """以管理员权限重新运行程序"""
    try:
        if sys.argv[0].endswith('.py'):
            # 如果是Python脚本
            script = os.path.abspath(sys.argv[0])
            cmd = f'python "{script}"'
        else:
            # 如果是可执行文件
            cmd = f'"{sys.argv[0]}"'
            
        ctypes.windll.shell32.ShellExecuteW(
            None, "runas", sys.executable, cmd, None, 1
        )
        return True
    except Exception as e:
        print(f"请求管理员权限失败: {e}")
        return False

# 在程序开始时检查管理员权限
if not is_admin():
    print("程序需要管理员权限运行，正在请求权限...")
    if run_as_admin():
        sys.exit(0)
    else:
        print("无法获取管理员权限，程序退出")
        input("按回车键退出...")
        sys.exit(1)

# 以下是原有的客户端代码
import threading
import time
import requests
import psutil
import json
from datetime import datetime
from PIL import Image, ImageDraw
import pystray
import tkinter as tk
from tkinter import ttk, simpledialog, messagebox, scrolledtext
import socket
import urllib3
import configparser
import base64

# 禁用SSL警告
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

class ZosTrayClient:
    def __init__(self):
        self.config_file = r"C:\ZosIPLogs\client_config.ini"
        self.load_config()
        
        self.mac_address = self.get_mac_address()
        self.hostname = os.environ['COMPUTERNAME']
        self.current_ip = self.get_current_ip()
        self.configured_ip = None
        self.is_running = True
        
        # 服务端通信配置
        self.server_port = self.config.getint('Client', 'server_port')
        self.server_socket = None
        self.command_handlers = {
            'get_info': self.handle_get_info,
            'get_detailed_info': self.handle_get_detailed_info,
            'execute_command': self.handle_execute_command,
            'reboot': self.handle_reboot,
            'shutdown': self.handle_shutdown,
            'update_ip': self.handle_update_ip,  # 这个处理所有网络配置
            'update_hostname': self.handle_update_hostname,
            'wake_on_lan': self.handle_wake_on_lan,
            'get_system_info': self.handle_get_system_info,
            'ping': self.handle_ping,
            'distribute_file': self.handle_distribute_file,
        }
        
        # 文件存储目录
        self.received_files_dir = r"C:\ZosIPLogs\ReceivedFiles"
        os.makedirs(self.received_files_dir, exist_ok=True)
        
        # 防止重复弹窗的标志
        self.is_network_change_in_progress = False
        self.is_hostname_change_in_progress = False
        
        # 隐藏控制台
        self.hide_console()
        
        # 启动服务端监听
        self.start_server_listener()
        
        # 创建系统托盘图标
        self.setup_tray_icon()
        
        self.log_action(f"ZOS IP客户端启动 - IP: {self.current_ip}, 端口: {self.server_port}")
        
        # 防止重复执行的标志
        self.is_shutdown_in_progress = False
        self.is_reboot_in_progress = False
    def load_config(self):
        """加载配置文件"""
        self.config = configparser.ConfigParser()
        if not os.path.exists(self.config_file):
            os.makedirs(os.path.dirname(self.config_file), exist_ok=True)
            
        self.config.read(self.config_file, encoding='utf-8')
        
        if not self.config.has_section('Client'):
            self.config.add_section('Client')
        
        defaults = {
            'zos_server': '192.168.1.100',
            'check_interval': '300',
            'task_check_interval': '30',
            'exit_password': 'love00',
            'auto_update': 'true',
            'enable_logging': 'true',
            'server_port': '8888'
        }
        
        for key, value in defaults.items():
            if not self.config.has_option('Client', key):
                self.config.set('Client', key, value)
        
        self.zos_server = self.config.get('Client', 'zos_server')
        self.check_interval = self.config.getint('Client', 'check_interval')
        self.task_check_interval = self.config.getint('Client', 'task_check_interval')
        self.exit_password = self.config.get('Client', 'exit_password')
        self.auto_update = self.config.getboolean('Client', 'auto_update')
        self.enable_logging = self.config.getboolean('Client', 'enable_logging')
        
        self.save_config()
    
    def save_config(self):
        """保存配置文件"""
        try:
            with open(self.config_file, 'w', encoding='utf-8') as f:
                self.config.write(f)
        except Exception as e:
            print(f"保存配置失败: {e}")

    def hide_console(self):
        """隐藏控制台窗口"""
        try:
            ctypes.windll.user32.ShowWindow(ctypes.windll.kernel32.GetConsoleWindow(), 0)
        except:
            pass

    def start_server_listener(self):
        """启动服务端监听"""
        max_retries = 3
        retry_count = 0
        
        while retry_count < max_retries:
            try:
                self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
                self.server_socket.bind(('0.0.0.0', self.server_port))
                self.server_socket.listen(5)
                self.server_socket.settimeout(1)
                
                self.listener_thread = threading.Thread(target=self.server_listener_loop, daemon=True)
                self.listener_thread.start()
                
                self.log_action(f"✅ 服务端监听启动成功，端口: {self.server_port}")
                return
                
            except OSError as e:
                if "10048" in str(e):
                    self.server_port += 1
                    self.log_action(f"端口被占用，尝试端口: {self.server_port}")
                    retry_count += 1
                    time.sleep(1)
                else:
                    self.log_action(f"❌ 启动服务端监听失败: {str(e)}")
                    break
            except Exception as e:
                self.log_action(f"❌ 启动服务端监听异常: {str(e)}")
                break
        
        if retry_count >= max_retries:
            self.log_action("❌ 无法启动服务端监听，请检查端口配置")

    def server_listener_loop(self):
        """服务端监听循环"""
        self.log_action("🔍 开始监听客户端连接...")
        
        while self.is_running:
            try:
                client_socket, client_address = self.server_socket.accept()
                self.log_action(f"📡 收到来自 {client_address} 的连接")
                
                client_socket.settimeout(30)
                
                client_thread = threading.Thread(
                    target=self.handle_client_request, 
                    args=(client_socket, client_address),
                    daemon=True
                )
                client_thread.start()
                
            except socket.timeout:
                continue
            except Exception as e:
                if self.is_running:
                    self.log_action(f"⚠️ 监听异常: {str(e)}")
                break
        
        self.log_action("🛑 服务端监听已停止")

    def handle_client_request(self, client_socket, client_address):
        """处理客户端请求"""
        try:
            data = b""
            client_socket.settimeout(10)
            
            while True:
                chunk = client_socket.recv(4096)
                if not chunk:
                    break
                data += chunk
                if len(chunk) < 4096:
                    break

            if not data:
                self.log_action(f"📭 收到空数据 from {client_address}")
                client_socket.close()
                return
                
            try:
                request_str = data.decode('utf-8').strip()
                request = json.loads(request_str)
                action = request.get('action')
                
                self.log_action(f"📨 处理请求: {action} from {client_address}")
                
                if action in self.command_handlers:
                    response = self.command_handlers[action](request)
                else:
                    response = {
                        'status': 'error',
                        'message': f'未知操作: {action}'
                    }
                
                response_data = json.dumps(response, ensure_ascii=False).encode('utf-8')
                try:
                    client_socket.send(response_data)
                    self.log_action(f"📤 响应发送成功 to {client_address}")
                except (BrokenPipeError, ConnectionResetError, ConnectionAbortedError) as e:
                    self.log_action(f"📤 发送响应时连接已关闭: {client_address} - {str(e)}")
                
            except json.JSONDecodeError as e:
                self.log_action(f"❌ JSON解析失败: {str(e)}")
                response = {
                    'status': 'error',
                    'message': '无效的JSON数据'
                }
                try:
                    client_socket.send(json.dumps(response).encode('utf-8'))
                except:
                    pass
                    
        except (ConnectionResetError, ConnectionAbortedError, BrokenPipeError) as e:
            self.log_action(f"🔌 连接被客户端关闭: {client_address} - {str(e)}")
        except socket.timeout:
            self.log_action(f"⏰ 请求处理超时: {client_address}")
        except Exception as e:
            self.log_action(f"💥 处理请求异常: {str(e)}")
            try:
                response = {
                    'status': 'error',
                    'message': f'处理失败: {str(e)}'
                }
                client_socket.send(json.dumps(response).encode('utf-8'))
            except:
                pass
        finally:
            try:
                client_socket.close()
            except:
                pass

    def handle_ping(self, request):
        """处理ping请求"""
        try:
            self.log_action("🏓 收到ping请求")
            return {
                'status': 'success',
                'message': 'pong',
                'data': {
                    'hostname': self.hostname,
                    'ip': self.current_ip,
                    'mac': self.mac_address,
                    'timestamp': datetime.now().isoformat(),
                    'version': '2.0'
                }
            }
        except Exception as e:
            return {
                'status': 'error',
                'message': f'ping处理失败: {str(e)}'
            }

    def handle_get_info(self, request):
        """处理获取基本信息请求 - 确保与服务器端兼容"""
        try:
            return {
                'status': 'success',  # 添加status字段
                'type': 'zos_ip_client',  # 确保有type字段
                'hostname': self.hostname,
                'ip': self.current_ip,
                'mac': self.mac_address,
                'version': '2.0',
                'server_port': self.server_port,
                'last_seen': datetime.now().isoformat()
            }
        except Exception as e:
            return {
                'status': 'error',
                'message': f'获取信息失败: {str(e)}'
            }

    def handle_get_detailed_info(self, request):
        """处理获取详细信息请求"""
        try:
            cpu_percent = psutil.cpu_percent(interval=0.1)
            memory = psutil.virtual_memory()
            disk = psutil.disk_usage('C:\\')
            gateway = self.get_gateway()
            dns_servers = self.get_dns_servers()
            subnet_mask = self.get_subnet_mask()
            
            return {
                'status': 'success',
                'system_info': {
                    'os': f"Windows {os.environ.get('OS', 'Unknown')}",
                    'cpu_usage': f"{cpu_percent}%",
                    'memory_usage': f"{memory.percent}%",
                    'disk_space': f"{disk.percent}% used, {disk.free // (1024**3)}GB free"
                },
                'network_info': {
                    'subnet_mask': subnet_mask,
                    'gateway': gateway,
                    'dns_servers': dns_servers,
                    'adapter': self.get_network_adapter()
                },
                'client_info': {
                    'hostname': self.hostname,
                    'ip': self.current_ip,
                    'mac': self.mac_address,
                    'configured_ip': self.configured_ip,
                    'version': '2.0'
                }
            }
        except Exception as e:
            return {
                'status': 'error',
                'message': f'获取详细信息失败: {str(e)}'
            }

    def handle_execute_command(self, request):
        """处理执行命令请求"""
        try:
            command = request.get('command', '')
            if not command:
                return {'status': 'error', 'message': '命令为空'}
                
            self.log_action(f"执行远程命令: {command}")
            
            # 使用subprocess运行命令，不创建窗口
            result = subprocess.run(
                command, 
                shell=True, 
                capture_output=True, 
                text=True,
                timeout=30,
                creationflags=subprocess.CREATE_NO_WINDOW
            )
            
            return {
                'status': 'success',
                'returncode': result.returncode,
                'stdout': result.stdout,
                'stderr': result.stderr
            }
            
        except subprocess.TimeoutExpired:
            return {'status': 'error', 'message': '命令执行超时'}
        except Exception as e:
            return {'status': 'error', 'message': f'执行命令失败: {str(e)}'}

    #处理重启和关机请求1
    def handle_reboot(self, request):
        """处理重启请求 - 避免重复确认"""
        try:
            # 检查是否已经有重启在进行中
            if hasattr(self, 'is_reboot_in_progress') and self.is_reboot_in_progress:
                self.log_action("重启操作正在进行中，忽略重复请求")
                return {'status': 'success', 'message': '重启操作正在进行中'}
                
            self.is_reboot_in_progress = True
            self.log_action("收到远程重启命令")
            
            # 使用现有的show_countdown_dialog_enhanced函数
            if self.show_countdown_dialog_enhanced(
                "远程重启确认",
                "服务器请求重启您的计算机。\n\n⚠️ 警告：所有未保存的工作将会丢失！\n请及时保存您的文档和数据。",
                'reboot',
                timeout=15
            ):
                self.log_action("用户确认重启")
                # 命令已经在show_countdown_dialog_enhanced中执行了
                return {'status': 'success', 'message': '计算机正在重启...'}
            else:
                self.log_action("用户取消重启")
                return {'status': 'cancelled', 'message': '用户取消重启'}
                
        except Exception as e:
            error_msg = f'重启失败: {str(e)}'
            self.log_action(error_msg)
            return {'status': 'error', 'message': error_msg}
        finally:
            # 重置标志
            self.is_reboot_in_progress = False

    def handle_shutdown(self, request):
        """处理关机请求 - 避免重复确认"""
        try:
            # 检查是否已经有关机在进行中
            if hasattr(self, 'is_shutdown_in_progress') and self.is_shutdown_in_progress:
                self.log_action("关机操作正在进行中，忽略重复请求")
                return {'status': 'success', 'message': '关机操作正在进行中'}
                
            self.is_shutdown_in_progress = True
            self.log_action("收到远程关机命令")
            
            # 使用现有的show_countdown_dialog_enhanced函数
            if self.show_countdown_dialog_enhanced(
                "远程关机确认",
                "服务器请求关闭您的计算机。\n\n⚠️ 警告：所有未保存的工作将会丢失！\n请及时保存您的文档和数据。",
                'shutdown',
                timeout=15
            ):
                self.log_action("用户确认关机")
                # 命令已经在show_countdown_dialog_enhanced中执行了
                return {'status': 'success', 'message': '计算机正在关闭...'}
            else:
                self.log_action("用户取消关机")
                return {'status': 'cancelled', 'message': '用户取消关机'}
                
        except Exception as e:
            error_msg = f'关机失败: {str(e)}'
            self.log_action(error_msg)
            return {'status': 'error', 'message': error_msg}
        finally:
            # 重置标志
            self.is_shutdown_in_progress = False

    #处理重启和关机请求2


    def handle_update_ip(self, request):
        """处理更新网络配置请求 - 合并IP和DNS修改"""
        try:
            # 如果已经有网络变更在进行中，直接返回
            if self.is_network_change_in_progress:
                self.log_action("网络变更正在进行中，忽略重复请求")
                return {'status': 'success', 'message': '网络变更正在进行中'}
                
            new_ip = request.get('new_ip')
            gateway = request.get('gateway', '')
            subnet_mask = request.get('subnet_mask', '')
            dns_servers = request.get('dns_servers', [])

            # 检查是否有配置需要更新
            has_ip_change = new_ip and new_ip != self.current_ip
            has_dns_change = bool(dns_servers)
            
            if not has_ip_change and not has_dns_change:
                return {'status': 'error', 'message': '未提供有效的网络配置变更'}
            
            # 设置网络变更标志
            self.is_network_change_in_progress = True
            
            # 记录变更信息
            if has_ip_change:
                self.log_action(f"远程请求更新IP: {self.current_ip} -> {new_ip}")
            if has_dns_change:
                self.log_action(f"远程请求更新DNS: {dns_servers}")
            
            # 自动填充缺失的配置
            if has_ip_change:
                if not gateway:
                    parts = new_ip.split('.')
                    gateway = f"{parts[0]}.{parts[1]}.{parts[2]}.1"
                
                if not subnet_mask:
                    subnet_mask = "255.255.255.0"
            
            # 如果没有提供DNS服务器，使用默认值
            if not dns_servers:
                dns_servers = ['8.8.8.8', '114.114.114.114']
            
            # 确定变更类型和标题
            if has_ip_change and has_dns_change:
                title = "远程网络配置更新确认"
                change_type = 'both'
                message = "服务器请求更新您的网络配置（IP地址和DNS）"
            elif has_ip_change:
                title = "远程IP更新确认"
                change_type = 'ip'
                message = "服务器请求更新您的IP地址配置"
            else:
                title = "远程DNS更新确认" 
                change_type = 'dns'
                message = "服务器请求更新您的DNS配置"
            
            # 显示确认窗口并执行修改
            success = self.show_countdown_dialog_for_network_change(
                title,
                message,
                self.current_ip,
                new_ip if has_ip_change else self.current_ip,
                gateway,
                subnet_mask,
                dns_servers,
                timeout=15,
                change_type=change_type
            )
            
            # 重置网络变更标志
            self.is_network_change_in_progress = False
            
            if success:
                if change_type == 'both':
                    return {'status': 'success', 'message': f'网络配置已更新: {self.current_ip} -> {new_ip}, DNS: {dns_servers}'}
                elif change_type == 'ip':
                    return {'status': 'success', 'message': f'IP地址已更新: {self.current_ip} -> {new_ip}'}
                else:
                    return {'status': 'success', 'message': f'DNS配置已更新: {dns_servers}'}
            else:
                return {'status': 'cancelled', 'message': '用户取消网络配置更新'}
                    
        except Exception as e:
            # 确保在异常情况下也重置标志
            self.is_network_change_in_progress = False
            return {'status': 'error', 'message': f'更新网络配置失败: {str(e)}'}

    #重命名后重启
    def handle_update_hostname(self, request):
        """处理修改计算机名请求 - 确保弹窗显示"""
        try:
            new_hostname = request.get('new_hostname')
            if not new_hostname:
                return {'status': 'error', 'message': '未提供新计算机名'}
                
            self.log_action(f"远程请求修改计算机名: {self.hostname} -> {new_hostname}")
            
            # 在主线程中显示弹窗
            import threading
            
            result = {'confirmed': False}
            
            def show_dialog():
                try:
                    import tkinter as tk
                    root = tk.Tk()
                    root.withdraw()  # 隐藏主窗口
                    
                    # 创建对话框
                    dialog = tk.Toplevel(root)
                    dialog.title("修改计算机名确认")
                    dialog.geometry("450x250")
                    dialog.resizable(False, False)
                    dialog.attributes('-topmost', True)
                    
                    # 居中显示
                    dialog.update_idletasks()
                    screen_width = dialog.winfo_screenwidth()
                    screen_height = dialog.winfo_screenheight()
                    x = (screen_width - 450) // 2
                    y = (screen_height - 250) // 2
                    dialog.geometry(f"450x250+{x}+{y}")
                    
                    # 内容
                    tk.Label(dialog, text="⚠️ 修改计算机名确认", 
                            font=("Arial", 14, "bold"), fg="red").pack(pady=15)
                    
                    tk.Label(dialog, 
                            text=f"当前计算机名: {self.hostname}\n新计算机名: {new_hostname}\n\n修改后将立即重启计算机！",
                            font=("Arial", 10), justify=tk.LEFT).pack(pady=10)
                    
                    # 倒计时显示
                    countdown_var = tk.StringVar(value="3秒后自动重启")
                    countdown_label = tk.Label(dialog, textvariable=countdown_var,
                                            font=("Arial", 11, "bold"), fg="blue")
                    countdown_label.pack(pady=5)
                    
                    # 按钮框架
                    button_frame = tk.Frame(dialog)
                    button_frame.pack(pady=15)
                    
                    def on_confirm():
                        result['confirmed'] = True
                        dialog.destroy()
                        root.quit()
                    
                    def on_cancel():
                        result['confirmed'] = False
                        dialog.destroy()
                        root.quit()
                    
                    confirm_btn = tk.Button(button_frame, text="确定(3)", command=on_confirm, 
                                        width=12, bg="green", fg="white", font=("Arial", 10))
                    confirm_btn.pack(side=tk.LEFT, padx=10)
                    
                    cancel_btn = tk.Button(button_frame, text="取消", command=on_cancel, 
                                        width=12, bg="red", fg="white", font=("Arial", 10))
                    cancel_btn.pack(side=tk.LEFT, padx=10)
                    
                    # 倒计时逻辑
                    remaining = 3
                    
                    def update_countdown():
                        nonlocal remaining
                        if remaining > 0 and dialog.winfo_exists():
                            confirm_btn.config(text=f"确定({remaining})")
                            countdown_var.set(f"{remaining}秒后自动重启")
                            remaining -= 1
                            dialog.after(1000, update_countdown)
                        elif dialog.winfo_exists():
                            # 倒计时结束，自动确认
                            on_confirm()
                    
                    # 启动倒计时
                    dialog.after(1000, update_countdown)
                    
                    # 绑定按键
                    dialog.bind('<Return>', lambda e: on_confirm())
                    dialog.bind('<Escape>', lambda e: on_cancel())
                    
                    # 聚焦到对话框
                    dialog.focus_set()
                    
                    # 运行对话框
                    root.mainloop()
                    
                except Exception as e:
                    self.log_action(f"显示弹窗失败: {str(e)}")
                    result['confirmed'] = False
            
            # 在新线程中显示弹窗
            dialog_thread = threading.Thread(target=show_dialog)
            dialog_thread.daemon = True
            dialog_thread.start()
            dialog_thread.join(timeout=10)  # 等待最多10秒
            
            if not result['confirmed']:
                self.log_action("用户取消或弹窗超时")
                return {'status': 'cancelled', 'message': '用户取消修改'}
            
            # 执行计算机名修改
            self.log_action("开始修改计算机名...")
            success = self.update_computer_name(new_hostname)
            
            if not success:
                return {'status': 'error', 'message': '计算机名修改失败'}
            
            self.log_action("计算机名修改成功，立即重启")
            
            # 显示重启提示
            self.show_restart_notice()
            
            # 执行重启
            self.execute_restart_now()
            
            return {'status': 'success', 'message': f'计算机名已修改为: {self.hostname}, 系统正在重启'}
                
        except Exception as e:
            self.log_action(f"修改计算机名异常: {str(e)}")
            return {'status': 'error', 'message': f'修改计算机名失败: {str(e)}'}

    def show_restart_notice(self):
        """显示重启提示"""
        try:
            import tkinter as tk
            from tkinter import messagebox
            
            root = tk.Tk()
            root.withdraw()
            messagebox.showinfo("重启提示", "计算机名修改完成！\n系统即将重启...")
            root.destroy()
        except:
            pass

    def execute_restart_now(self):
        """立即重启"""
        try:
            self.log_action("执行重启命令...")
            
            # 使用shutdown命令重启
            import subprocess
            subprocess.run("shutdown /r /t 3 /f", shell=True, timeout=5)
            self.log_action("重启命令执行成功")
            
        except Exception as e:
            self.log_action(f"重启失败: {str(e)}")
            # 备用方法
            try:
                subprocess.run("powershell -Command \"Restart-Computer -Force\"", shell=True, timeout=5)
            except:
                pass
    #重命名后重启
    def handle_wake_on_lan(self, request):
        """处理网络唤醒请求"""
        try:
            target_mac = request.get('mac_address')
            if not target_mac:
                return {'status': 'error', 'message': '未提供MAC地址'}
                
            self.log_action(f"网络唤醒请求: {target_mac}")
            return {'status': 'success', 'message': '网络唤醒命令已发送'}
            
        except Exception as e:
            return {'status': 'error', 'message': f'网络唤醒失败: {str(e)}'}

    def handle_get_system_info(self, request):
        """处理获取系统信息请求"""
        try:
            system_info = self.get_detailed_system_info()
            return {
                'status': 'success',
                'system_info': system_info
            }
        except Exception as e:
            return {'status': 'error', 'message': f'获取系统信息失败: {str(e)}'}

    def handle_distribute_file(self, request):
        """处理文件分发请求"""
        try:
            filename = request.get('filename')
            file_content_b64 = request.get('file_content')
            target_path = request.get('target_path', '')
            
            if not filename or not file_content_b64:
                return {'status': 'error', 'message': '文件名或文件内容为空'}
            
            self.log_action(f"收到文件分发请求: {filename}")
            
            # 解码文件内容
            try:
                file_content = base64.b64decode(file_content_b64)
            except Exception as e:
                return {'status': 'error', 'message': f'文件内容解码失败: {str(e)}'}
            
            # 确定保存路径
            if target_path:
                save_path = target_path
                save_dir = os.path.dirname(save_path)
            else:
                save_dir = self.received_files_dir
                save_path = os.path.join(save_dir, filename)
            
            # 确保目录存在
            os.makedirs(save_dir, exist_ok=True)
            
            # 保存文件
            with open(save_path, 'wb') as f:
                f.write(file_content)
            
            file_size = len(file_content)
            self.log_action(f"文件保存成功: {save_path} ({file_size} 字节)")
            
            # 显示接收通知
            self.show_file_received_notification(filename, save_path, file_size)
            
            return {
                'status': 'success', 
                'message': f'文件接收成功: {filename}',
                'saved_path': save_path,
                'file_size': file_size
            }
            
        except Exception as e:
            error_msg = f'文件接收失败: {str(e)}'
            self.log_action(error_msg)
            return {'status': 'error', 'message': error_msg}

    def show_countdown_dialog_enhanced(self, title, message, command_type, timeout=15):
        """显示增强版倒计时确认对话框 - 修复倒计时显示"""
        result = [None]
        
        def execute_command():
            """执行系统命令"""
            try:
                if command_type == 'reboot':
                    self.log_action("执行重启命令")
                    # 使用3秒延迟，给用户看到反馈的时间
                    subprocess.run(["shutdown", "/r", "/t", "3", "/f"], check=True, 
                                creationflags=subprocess.CREATE_NO_WINDOW)
                elif command_type == 'shutdown':
                    self.log_action("执行关机命令")
                    subprocess.run(["shutdown", "/s", "/t", "3", "/f"], check=True, 
                                creationflags=subprocess.CREATE_NO_WINDOW)
            except Exception as e:
                self.log_action(f"执行{command_type}命令失败: {str(e)}")
        
        def show_dialog():
            cancelled = [False]
            remaining_time = timeout
            
            countdown_window = tk.Tk()
            countdown_window.title(title)
            countdown_window.geometry("500x300")
            countdown_window.resizable(False, False)
            countdown_window.attributes('-topmost', True)
            self.set_window_icon(countdown_window)
            
            # 设置窗口关闭事件
            def on_closing():
                nonlocal cancelled
                cancelled[0] = True
                result[0] = False
                try:
                    countdown_window.destroy()
                except:
                    pass
                self.log_action(f"用户关闭了{title}窗口")
            
            countdown_window.protocol("WM_DELETE_WINDOW", on_closing)
            
            # 居中显示
            countdown_window.update_idletasks()
            x = (countdown_window.winfo_screenwidth() // 2) - (500 // 2)
            y = (countdown_window.winfo_screenheight() // 2) - (300 // 2)
            countdown_window.geometry(f'500x300+{x}+{y}')
            
            style = ttk.Style()
            style.configure("Green.Horizontal.TProgressbar", troughcolor='white', background='green')
            style.configure("Orange.Horizontal.TProgressbar", troughcolor='white', background='orange')
            style.configure("Red.Horizontal.TProgressbar", troughcolor='white', background='red')
            
            message_frame = ttk.Frame(countdown_window)
            message_frame.pack(fill=tk.BOTH, expand=True, padx=25, pady=20)
            
            header_frame = ttk.Frame(message_frame)
            header_frame.pack(fill=tk.X, pady=(0, 15))
            
            warning_label = ttk.Label(header_frame, text="⚠️", font=("Arial", 20))
            warning_label.pack(side=tk.LEFT, padx=(0, 10))
            
            title_label = ttk.Label(header_frame, text=title, font=("Arial", 12, "bold"), foreground="red")
            title_label.pack(side=tk.LEFT)
            
            message_label = ttk.Label(message_frame, text=message, font=("Arial", 10), wraplength=450, justify=tk.LEFT)
            message_label.pack(fill=tk.X, pady=(0, 15))
            
            countdown_frame = ttk.Frame(message_frame)
            countdown_frame.pack(fill=tk.X, pady=(0, 10))
            
            ttk.Label(countdown_frame, text="剩余时间:", font=("Arial", 9)).pack(side=tk.LEFT)
            countdown_var = tk.StringVar(value=f"{timeout} 秒")
            countdown_label = ttk.Label(countdown_frame, textvariable=countdown_var, font=("Arial", 10, "bold"), foreground="blue")
            countdown_label.pack(side=tk.LEFT, padx=(5, 0))
            
            progress_bar = ttk.Progressbar(message_frame, orient="horizontal", length=450, mode="determinate", style="Green.Horizontal.TProgressbar")
            progress_bar.pack(fill=tk.X, pady=(0, 20))
            progress_bar['maximum'] = timeout
            progress_bar['value'] = 0
            
            button_frame = ttk.Frame(message_frame)
            button_frame.pack(fill=tk.X)
            
            hint_label = ttk.Label(button_frame, text="请及时保存您的工作！", font=("Arial", 9, "italic"), foreground="gray")
            hint_label.pack(side=tk.LEFT)
            
            def cancel_command():
                nonlocal cancelled
                cancelled[0] = True
                result[0] = False
                self.log_action(f"用户取消了{title}")
                countdown_window.destroy()
            
            cancel_button = ttk.Button(button_frame, text="取消操作", command=cancel_command, width=12)
            cancel_button.pack(side=tk.RIGHT, padx=(10, 0))
            
            def immediate_execute():
                result[0] = True
                self.log_action(f"用户立即执行{title}")
                # 执行命令
                execute_command()
                countdown_window.destroy()
            
            immediate_button = ttk.Button(button_frame, text="立即执行", command=immediate_execute, width=12)
            immediate_button.pack(side=tk.RIGHT)
            
            # 更新立即执行按钮的文本
            def update_immediate_button_text():
                if remaining_time > 0:
                    immediate_button.config(text=f"立即执行({remaining_time})")
                else:
                    immediate_button.config(text="立即执行")
            
            def update_countdown():
                nonlocal remaining_time, cancelled
                if remaining_time > 0 and not cancelled[0] and countdown_window.winfo_exists():
                    try:
                        # 更新倒计时显示
                        countdown_var.set(f"{remaining_time} 秒")
                        progress_bar['value'] = timeout - remaining_time
                        
                        # 更新立即执行按钮文本
                        update_immediate_button_text()
                        
                        # 更新颜色
                        if remaining_time <= 5:
                            countdown_label.configure(foreground="red")
                            progress_bar.configure(style="Red.Horizontal.TProgressbar")
                        elif remaining_time <= 10:
                            countdown_label.configure(foreground="orange")
                            progress_bar.configure(style="Orange.Horizontal.TProgressbar")
                        else:
                            countdown_label.configure(foreground="blue")
                            progress_bar.configure(style="Green.Horizontal.TProgressbar")
                        
                        remaining_time -= 1
                        countdown_window.after(1000, update_countdown)
                    except Exception as e:
                        # 如果窗口已经被销毁，直接返回
                        return
                elif not cancelled[0] and countdown_window.winfo_exists():
                    # 倒计时结束，自动执行
                    result[0] = True
                    self.log_action(f"倒计时结束，自动执行{title}")
                    execute_command()
                    countdown_window.destroy()
            
            # 初始更新按钮文本
            update_immediate_button_text()
            
            # 启动倒计时
            countdown_window.after(1000, update_countdown)
            
            # 运行主循环
            countdown_window.mainloop()
        
        # 在主线程中运行对话框
        import threading
        if threading.current_thread() is threading.main_thread():
            # 如果在主线程中，直接运行
            show_dialog()
        else:
            # 如果在其他线程中，使用after方法在主线程中运行
            def run_in_main_thread():
                show_dialog()
            
            # 创建一个隐藏的根窗口来使用after方法
            root = tk.Tk()
            root.withdraw()
            root.after(0, run_in_main_thread)
            root.mainloop()
        
        return result[0] if result[0] is not None else False

    def show_countdown_dialog_for_network_change(self, title, message, old_ip, new_ip, gateway, subnet_mask, dns_servers, timeout=15, change_type='ip'):
        """显示统一的网络配置变更确认对话框 - 修复Tkinter线程问题"""
        result = [None]
        change_applied = [False]  # 防止重复执行
        
        def apply_network_change():
            if change_applied[0]:
                return False
            change_applied[0] = True
        
            try:
                if change_type == 'dns':
                    # 仅更新DNS
                    success = self.update_dns_servers_only(dns_servers)
                    if success:
                        self.log_action(f"DNS配置更新成功: {dns_servers}")
                    return success
                else:
                    # 更新完整的网络配置（IP+网关+掩码+DNS）
                    success = self.update_static_ip_optimized(new_ip, gateway, subnet_mask, dns_servers)
                    if success:
                        # 更新当前IP变量和托盘提示
                        old_ip_val = self.current_ip
                        self.current_ip = new_ip
                        self.update_tray_tooltip()
                        self.log_action(f"网络配置更新成功: {old_ip_val} -> {new_ip}, DNS: {dns_servers}")
                    return success
            except Exception as e:
                self.log_action(f"网络配置修改异常: {str(e)}")
                return False
    
        def show_dialog():
            try:
                cancelled = [False]
                remaining_time = timeout
            
                # 创建Tkinter窗口
                countdown_window = tk.Tk()
                countdown_window.title(title)
                countdown_window.geometry("550x400" if change_type == 'dns' else "550x420")
                countdown_window.resizable(False, False)
                countdown_window.attributes('-topmost', True)
                self.set_window_icon(countdown_window)
            
                # 设置窗口关闭事件
                def on_closing():
                    nonlocal cancelled
                    cancelled[0] = True
                    result[0] = False
                    try:
                        countdown_window.quit()
                        countdown_window.destroy()
                    except:
                        pass
                    self.log_action("用户关闭了确认窗口")
            
                countdown_window.protocol("WM_DELETE_WINDOW", on_closing)
            
                # 居中显示
                countdown_window.update_idletasks()
                x = (countdown_window.winfo_screenwidth() // 2) - (550 // 2)
                y = (countdown_window.winfo_screenheight() // 2) - (400 // 2)
                countdown_window.geometry(f'550x400+{x}+{y}')
            
                style = ttk.Style()
                style.configure("Green.Horizontal.TProgressbar", troughcolor='white', background='green')
                style.configure("Orange.Horizontal.TProgressbar", troughcolor='white', background='orange')
                style.configure("Red.Horizontal.TProgressbar", troughcolor='white', background='red')
            
                message_frame = ttk.Frame(countdown_window)
                message_frame.pack(fill=tk.BOTH, expand=True, padx=25, pady=20)
            
                header_frame = ttk.Frame(message_frame)
                header_frame.pack(fill=tk.X, pady=(0, 15))
            
                warning_label = ttk.Label(header_frame, text="⚠️", font=("Arial", 20))
                warning_label.pack(side=tk.LEFT, padx=(0, 10))
            
                title_label = ttk.Label(header_frame, text=title, font=("Arial", 12, "bold"), foreground="red")
                title_label.pack(side=tk.LEFT)
            
                details_frame = ttk.Frame(message_frame)
                details_frame.pack(fill=tk.X, pady=(0, 15))
            
                if change_type == 'dns':
                    # 仅DNS更新的显示内容
                    details_text = f"""DNS配置变更详情：

当前IP: {old_ip}
新DNS: {', '.join(dns_servers)}

⚠️ 注意：DNS变更不会影响当前网络连接！"""
                else:
                    # 完整网络配置更新的显示内容
                    details_text = f"""网络配置变更详情：

当前IP: {old_ip}
新IP: {new_ip}
网关: {gateway}
子网掩码: {subnet_mask}
DNS: {', '.join(dns_servers)}

⚠️ 注意：网络连接可能会暂时中断！"""
            
                details_label = ttk.Label(details_frame, text=details_text, font=("Arial", 9), wraplength=500, justify=tk.LEFT)
                details_label.pack(fill=tk.X)
            
                countdown_frame = ttk.Frame(message_frame)
                countdown_frame.pack(fill=tk.X, pady=(0, 10))
            
                # 使用普通的StringVar而不是tkinter变量
                countdown_text = f"{timeout} 秒"
                countdown_label = ttk.Label(countdown_frame, text=countdown_text, font=("Arial", 10, "bold"), foreground="blue")
                countdown_label.pack(side=tk.LEFT, padx=(5, 0))
            
                progress_bar = ttk.Progressbar(message_frame, orient="horizontal", length=500, mode="determinate", style="Green.Horizontal.TProgressbar")
                progress_bar.pack(fill=tk.X, pady=(0, 20))
                progress_bar['maximum'] = 100
                progress_bar['value'] = 0
            
                button_frame = ttk.Frame(message_frame)
                button_frame.pack(fill=tk.X)
            
                if change_type == 'dns':
                    hint_text = "DNS变更通常不会中断网络连接！"
                else:
                    hint_text = "网络变更期间请勿断开电源！"
                
                hint_label = ttk.Label(button_frame, text=hint_text, font=("Arial", 9, "italic"), foreground="gray")
                hint_label.pack(side=tk.LEFT)
            
                def cancel_change():
                    nonlocal cancelled
                    cancelled[0] = True
                    result[0] = False
                    try:
                        countdown_window.quit()
                        countdown_window.destroy()
                    except:
                        pass
                    self.log_action("用户取消了网络配置修改")
            
                cancel_button = ttk.Button(button_frame, text="取消修改", command=cancel_change, width=12)
                cancel_button.pack(side=tk.RIGHT, padx=(10, 0))
            
                def immediate_apply():
                    result[0] = True
                    try:
                        countdown_window.quit()
                        countdown_window.destroy()
                    except:
                        pass
                    # 执行网络配置修改
                    apply_network_change()
            
                immediate_button = ttk.Button(button_frame, text="立即应用", command=immediate_apply, width=12)
                immediate_button.pack(side=tk.RIGHT)
            
                def update_countdown():
                    nonlocal remaining_time, cancelled
                    if remaining_time > 0 and not cancelled[0]:
                        try:
                            # 直接更新标签文本，不使用StringVar
                            new_text = f"{remaining_time} 秒"
                            countdown_label.config(text=new_text)
                        
                            progress_value = (timeout - remaining_time) / timeout * 100
                            progress_bar['value'] = progress_value
                        
                            if remaining_time <= 5:
                                countdown_label.configure(foreground="red")
                                progress_bar.configure(style="Red.Horizontal.TProgressbar")
                            elif remaining_time <= 10:
                                countdown_label.configure(foreground="orange")
                                progress_bar.configure(style="Orange.Horizontal.TProgressbar")
                            else:
                                countdown_label.configure(foreground="blue")
                                progress_bar.configure(style="Green.Horizontal.TProgressbar")
                        
                            remaining_time -= 1
                            if countdown_window.winfo_exists():
                                countdown_window.after(1000, update_countdown)
                        except Exception as e:
                            # 如果窗口已经被销毁，直接返回
                            return
                    elif not cancelled[0]:
                        result[0] = True
                        try:
                            countdown_window.quit()
                            countdown_window.destroy()
                        except:
                            pass
                        # 执行网络配置修改
                        apply_network_change()
            
                # 启动倒计时
                if countdown_window.winfo_exists():
                    countdown_window.after(1000, update_countdown)
            
                # 运行主循环
                countdown_window.mainloop()
            
            except Exception as e:
                self.log_action(f"显示确认窗口时出错: {str(e)}")
                result[0] = False
    
        # 在主线程中运行对话框
        import threading
        if threading.current_thread() is threading.main_thread():
            # 如果在主线程中，直接运行
            show_dialog()
        else:
            # 如果在其他线程中，使用after方法在主线程中运行
            def run_in_main_thread():
                show_dialog()
        
            # 创建一个隐藏的根窗口来使用after方法
            root = tk.Tk()
            root.withdraw()
            root.after(0, run_in_main_thread)
            root.mainloop()
    
        return result[0] if result[0] is not None else False

    def show_countdown_dialog_for_hostname_change(self, title, message, old_hostname, new_hostname, timeout=15):
        """显示计算机名修改确认对话框 - 参照IP修改的方法"""
        result = [None]
        change_applied = [False]  # 防止重复执行
        
        def apply_hostname_change():
            if change_applied[0]:
                return False
            change_applied[0] = True
            
            try:
                success = self.update_computer_name(new_hostname)
                if success:
                    self.log_action(f"计算机名修改成功: {old_hostname} -> {new_hostname}")
                return success
            except Exception as e:
                self.log_action(f"计算机名修改异常: {str(e)}")
                return False
        
        def show_dialog():
            try:
                cancelled = [False]
                remaining_time = timeout
                
                # 创建Tkinter窗口 - 参照IP修改的样式
                countdown_window = tk.Tk()
                countdown_window.title(title)
                countdown_window.geometry("550x400")
                countdown_window.resizable(False, False)
                countdown_window.attributes('-topmost', True)
                self.set_window_icon(countdown_window)
                
                # 设置窗口关闭事件
                def on_closing():
                    nonlocal cancelled
                    cancelled[0] = True
                    result[0] = False
                    try:
                        countdown_window.quit()
                        countdown_window.destroy()
                    except:
                        pass
                    self.log_action("用户关闭了计算机名修改确认窗口")
                
                countdown_window.protocol("WM_DELETE_WINDOW", on_closing)
                
                # 居中显示
                countdown_window.update_idletasks()
                x = (countdown_window.winfo_screenwidth() // 2) - (550 // 2)
                y = (countdown_window.winfo_screenheight() // 2) - (400 // 2)
                countdown_window.geometry(f'550x400+{x}+{y}')
                
                style = ttk.Style()
                style.configure("Green.Horizontal.TProgressbar", troughcolor='white', background='green')
                style.configure("Orange.Horizontal.TProgressbar", troughcolor='white', background='orange')
                style.configure("Red.Horizontal.TProgressbar", troughcolor='white', background='red')
                
                message_frame = ttk.Frame(countdown_window)
                message_frame.pack(fill=tk.BOTH, expand=True, padx=25, pady=20)
                
                header_frame = ttk.Frame(message_frame)
                header_frame.pack(fill=tk.X, pady=(0, 15))
                
                warning_label = ttk.Label(header_frame, text="⚠️", font=("Arial", 20))
                warning_label.pack(side=tk.LEFT, padx=(0, 10))
                
                title_label = ttk.Label(header_frame, text=title, font=("Arial", 12, "bold"), foreground="red")
                title_label.pack(side=tk.LEFT)
                
                details_frame = ttk.Frame(message_frame)
                details_frame.pack(fill=tk.X, pady=(0, 15))
                
                # 计算机名变更详情
                details_text = f"""计算机名变更详情：

当前计算机名: {old_hostname}
新计算机名: {new_hostname}

⚠️ 重要提示：
- 计算机名修改后需要重启才能生效
- 重启后网络连接可能会暂时中断
- 请确保新计算机名符合命名规范"""
                
                details_label = ttk.Label(details_frame, text=details_text, font=("Arial", 9), wraplength=500, justify=tk.LEFT)
                details_label.pack(fill=tk.X)
                
                countdown_frame = ttk.Frame(message_frame)
                countdown_frame.pack(fill=tk.X, pady=(0, 10))
                
                # 使用普通的StringVar而不是tkinter变量
                countdown_text = f"{timeout} 秒"
                countdown_label = ttk.Label(countdown_frame, text=countdown_text, font=("Arial", 10, "bold"), foreground="blue")
                countdown_label.pack(side=tk.LEFT, padx=(5, 0))
                
                progress_bar = ttk.Progressbar(message_frame, orient="horizontal", length=500, mode="determinate", style="Green.Horizontal.TProgressbar")
                progress_bar.pack(fill=tk.X, pady=(0, 20))
                progress_bar['maximum'] = 100
                progress_bar['value'] = 0
                
                button_frame = ttk.Frame(message_frame)
                button_frame.pack(fill=tk.X)
                
                hint_label = ttk.Label(button_frame, text="修改后需要重启计算机！", font=("Arial", 9, "italic"), foreground="gray")
                hint_label.pack(side=tk.LEFT)
                
                def cancel_change():
                    nonlocal cancelled
                    cancelled[0] = True
                    result[0] = False
                    try:
                        countdown_window.quit()
                        countdown_window.destroy()
                    except:
                        pass
                    self.log_action("用户取消了计算机名修改")
                
                cancel_button = ttk.Button(button_frame, text="取消修改", command=cancel_change, width=12)
                cancel_button.pack(side=tk.RIGHT, padx=(10, 0))
                
                def immediate_apply():
                    result[0] = True
                    try:
                        countdown_window.quit()
                        countdown_window.destroy()
                    except:
                        pass
                    # 执行计算机名修改
                    apply_hostname_change()
                
                immediate_button = ttk.Button(button_frame, text="立即应用", command=immediate_apply, width=12)
                immediate_button.pack(side=tk.RIGHT)
                
                def update_countdown():
                    nonlocal remaining_time, cancelled
                    if remaining_time > 0 and not cancelled[0]:
                        try:
                            # 直接更新标签文本，不使用StringVar
                            new_text = f"{remaining_time} 秒"
                            countdown_label.config(text=new_text)
                            
                            progress_value = (timeout - remaining_time) / timeout * 100
                            progress_bar['value'] = progress_value
                            
                            if remaining_time <= 5:
                                countdown_label.configure(foreground="red")
                                progress_bar.configure(style="Red.Horizontal.TProgressbar")
                            elif remaining_time <= 10:
                                countdown_label.configure(foreground="orange")
                                progress_bar.configure(style="Orange.Horizontal.TProgressbar")
                            else:
                                countdown_label.configure(foreground="blue")
                                progress_bar.configure(style="Green.Horizontal.TProgressbar")
                            
                            remaining_time -= 1
                            if countdown_window.winfo_exists():
                                countdown_window.after(1000, update_countdown)
                        except Exception as e:
                            # 如果窗口已经被销毁，直接返回
                            return
                    elif not cancelled[0]:
                        result[0] = True
                        try:
                            countdown_window.quit()
                            countdown_window.destroy()
                        except:
                            pass
                        # 执行计算机名修改
                        apply_hostname_change()
                
                # 启动倒计时
                if countdown_window.winfo_exists():
                    countdown_window.after(1000, update_countdown)
                
                # 运行主循环
                countdown_window.mainloop()
                
            except Exception as e:
                self.log_action(f"显示计算机名修改确认窗口时出错: {str(e)}")
                result[0] = False
        
        # 在主线程中运行对话框
        import threading
        if threading.current_thread() is threading.main_thread():
            # 如果在主线程中，直接运行
            show_dialog()
        else:
            # 如果在其他线程中，使用after方法在主线程中运行
            def run_in_main_thread():
                show_dialog()
            
            # 创建一个隐藏的根窗口来使用after方法
            root = tk.Tk()
            root.withdraw()
            root.after(0, run_in_main_thread)
            root.mainloop()
        
        return result[0] if result[0] is not None else False

    def show_auto_close_success_message(self, message, timeout=5):
        """显示成功消息并自动关闭"""
        def show_message():
            success_window = tk.Tk()
            success_window.title("操作成功")
            success_window.geometry("400x200")
            success_window.resizable(False, False)
            success_window.attributes('-topmost', True)
            self.set_window_icon(success_window)
            
            success_window.update_idletasks()
            x = (success_window.winfo_screenwidth() // 2) - (400 // 2)
            y = (success_window.winfo_screenheight() // 2) - (200 // 2)
            success_window.geometry(f'400x200+{x}+{y}')
            
            success_frame = ttk.Frame(success_window)
            success_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)
            
            success_icon = ttk.Label(success_frame, text="✅", font=("Arial", 24))
            success_icon.pack(pady=(0, 10))
            
            success_label = ttk.Label(success_frame, text=message, font=("Arial", 10), wraplength=360, justify=tk.CENTER, foreground="green")
            success_label.pack(fill=tk.X, pady=(0, 10))
            
            countdown_var = tk.StringVar(value=f"{timeout}秒后自动关闭")
            countdown_label = ttk.Label(success_frame, textvariable=countdown_var, font=("Arial", 9), foreground="gray")
            countdown_label.pack()
            
            def update_countdown(remaining):
                if remaining > 0 and success_window.winfo_exists():
                    countdown_var.set(f"{remaining}秒后自动关闭")
                    success_window.after(1000, update_countdown, remaining - 1)
                else:
                    success_window.destroy()
            
            def close_window():
                if success_window.winfo_exists():
                    success_window.destroy()
            
            success_window.after(1000, update_countdown, timeout - 1)
            success_window.after(timeout * 1000, close_window)
            success_window.mainloop()
        
        threading.Thread(target=show_message, daemon=True).start()

    def show_auto_close_error_message(self, message, timeout=5):
        """显示错误消息并自动关闭"""
        def show_message():
            error_window = tk.Tk()
            error_window.title("操作失败")
            error_window.geometry("400x200")
            error_window.resizable(False, False)
            error_window.attributes('-topmost', True)
            self.set_window_icon(error_window)
            
            error_window.update_idletasks()
            x = (error_window.winfo_screenwidth() // 2) - (400 // 2)
            y = (error_window.winfo_screenheight() // 2) - (200 // 2)
            error_window.geometry(f'400x200+{x}+{y}')
            
            error_frame = ttk.Frame(error_window)
            error_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)
            
            error_icon = ttk.Label(error_frame, text="❌", font=("Arial", 24))
            error_icon.pack(pady=(0, 10))
            
            error_label = ttk.Label(error_frame, text=message, font=("Arial", 10), wraplength=360, justify=tk.CENTER, foreground="red")
            error_label.pack(fill=tk.X, pady=(0, 10))
            
            countdown_var = tk.StringVar(value=f"{timeout}秒后自动关闭")
            countdown_label = ttk.Label(error_frame, textvariable=countdown_var, font=("Arial", 9), foreground="gray")
            countdown_label.pack()
            
            def update_countdown(remaining):
                if remaining > 0 and error_window.winfo_exists():
                    countdown_var.set(f"{remaining}秒后自动关闭")
                    error_window.after(1000, update_countdown, remaining - 1)
                else:
                    error_window.destroy()
            
            def close_window():
                if error_window.winfo_exists():
                    error_window.destroy()
            
            error_window.after(1000, update_countdown, timeout - 1)
            error_window.after(timeout * 1000, close_window)
            error_window.mainloop()
        
        threading.Thread(target=show_message, daemon=True).start()

    def show_file_received_notification(self, filename, filepath, filesize):
        """显示文件接收通知"""
        def show_notification():
            root = tk.Tk()
            root.withdraw()
            root.attributes('-topmost', True)
            
            # 格式化文件大小
            if filesize < 1024:
                size_str = f"{filesize} B"
            elif filesize < 1024 * 1024:
                size_str = f"{filesize/1024:.1f} KB"
            else:
                size_str = f"{filesize/(1024*1024):.1f} MB"
            
            message = f"""📥 收到新文件

文件名: {filename}
保存路径: {filepath}
文件大小: {size_str}

文件已保存到接收目录。"""
            
            # 显示消息框
            messagebox.showinfo("文件接收通知", message, parent=root)
            root.destroy()
        
        # 在新线程中显示通知，避免阻塞主线程
        threading.Thread(target=show_notification, daemon=True).start()

    def setup_tray_icon(self):
        """设置系统托盘图标"""
        try:
            from uwf import SimpleUWFManager
            UWF_AVAILABLE = True
        except ImportError:
            UWF_AVAILABLE = False
        menu_items = [
        pystray.MenuItem("📊 系统状态", self.show_system_status_menu),
        pystray.MenuItem("🔧 IP地址设置", self.manual_set_ip),
        pystray.MenuItem("🛡️ UWF分区保护", self.open_uwf_manager),  # 添加这一行
        pystray.MenuItem("📁 查看接收文件", self.show_received_files),
        pystray.MenuItem("⚙️ 客户端配置", self.client_settings),
        pystray.MenuItem("📋 查看日志", self.show_logs),
        pystray.Menu.SEPARATOR,
        pystray.MenuItem("🚪 退出程序", self.quit_app)
        ]
        
        menu = pystray.Menu(*menu_items)
        icon_image = self.load_icon_from_file()
        
        self.icon = pystray.Icon(
            "zos_ip_client",
            icon_image,
            self.get_tray_tooltip(),
            menu
        )
        
        self.monitor_thread = threading.Thread(target=self.monitor_loop, daemon=True)
        self.monitor_thread.start()
        
        self.task_thread = threading.Thread(target=self.task_monitor_loop, daemon=True)
        self.task_thread.start()
    def open_uwf_manager(self, icon=None, item=None):
        """打开UWF分区保护管理器"""
        try:
            from uwf import SimpleUWFManager
            # 在新线程中启动UWF管理器
            def run_uwf_manager():
                root = tk.Tk()
                app = SimpleUWFManager(root)
                root.mainloop()
            
            uwf_thread = threading.Thread(target=run_uwf_manager, daemon=True)
            uwf_thread.start()
            
        except Exception as e:
            self.show_error_message(f"打开UWF管理器失败: {str(e)}")
    def get_tray_tooltip(self):
        """获取托盘提示信息"""
        status = "运行中" if self.server_socket else "已停止"
        return f"""ZOS IP客户端 v2.0
主机: {self.hostname}
IP: {self.current_ip}
服务: {status}
端口: {self.server_port}"""

    def update_tray_tooltip(self):
        """更新托盘提示信息"""
        if hasattr(self, 'icon'):
            self.icon.title = self.get_tray_tooltip()

    def show_confirm_dialog(self, title, message):
        """显示确认对话框"""
        root = tk.Tk()
        root.withdraw()
        root.attributes('-topmost', True)
        self.set_window_icon(root)
        
        root.update_idletasks()
        width = 500
        height = 300
        x = (root.winfo_screenwidth() // 2) - (width // 2)
        y = (root.winfo_screenheight() // 2) - (height // 2)
        root.geometry(f'{width}x{height}+{x}+{y}')
        
        result = messagebox.askyesno(title, message, parent=root)
        root.destroy()
        return result

    def show_error_message(self, message):
        """显示错误消息"""
        root = tk.Tk()
        root.withdraw()
        root.attributes('-topmost', True)
        self.set_window_icon(root)
        
        root.update_idletasks()
        width = 400
        height = 200
        x = (root.winfo_screenwidth() // 2) - (width // 2)
        y = (root.winfo_screenheight() // 2) - (height // 2)
        root.geometry(f'{width}x{height}+{x}+{y}')
        
        messagebox.showerror("错误", message, parent=root)
        root.destroy()

    def show_success_message(self, message):
        """显示成功消息"""
        root = tk.Tk()
        root.withdraw()
        root.attributes('-topmost', True)
        self.set_window_icon(root)
        
        root.update_idletasks()
        width = 400
        height = 200
        x = (root.winfo_screenwidth() // 2) - (width // 2)
        y = (root.winfo_screenheight() // 2) - (height // 2)
        root.geometry(f'{width}x{height}+{x}+{y}')
        
        messagebox.showinfo("成功", message, parent=root)
        root.destroy()

    def show_info_message(self, title, message):
        """显示信息消息"""
        root = tk.Tk()
        root.withdraw()
        root.attributes('-topmost', True)
        self.set_window_icon(root)
        
        root.update_idletasks()
        width = 600
        height = 400
        x = (root.winfo_screenwidth() // 2) - (width // 2)
        y = (root.winfo_screenheight() // 2) - (height // 2)
        root.geometry(f'{width}x{height}+{x}+{y}')
        
        messagebox.showinfo(title, message, parent=root)
        root.destroy()

    def set_window_icon(self, window):
        """设置窗口图标"""
        try:
            icon_paths = [
                "favicon.ico",
                r"C:\ZosIPLogs\favicon.ico"
            ]
            
            for icon_path in icon_paths:
                if os.path.exists(icon_path):
                    window.iconbitmap(icon_path)
                    break
        except:
            pass

    def load_icon_from_file(self):
        """从文件加载图标"""
        try:
            icon_paths = [
                "favicon.ico",
                r"C:\ZosIPLogs\favicon.ico",
                os.path.join(os.path.dirname(__file__), "favicon.ico")
            ]
            
            for icon_path in icon_paths:
                if os.path.exists(icon_path):
                    image = Image.open(icon_path)
                    image = image.resize((64, 64), Image.Resampling.LANCZOS)
                    return image
            return self.create_beautiful_icon()
        except:
            return self.create_beautiful_icon()

    def create_beautiful_icon(self):
        """创建美观的图标"""
        image = Image.new('RGBA', (64, 64), (240, 248, 255, 0))
        draw = ImageDraw.Draw(image)
        
        for i in range(20, 0, -2):
            alpha = 100 - i * 3
            draw.ellipse([i, i, 64-i, 64-i], fill=(70, 130, 180, alpha))
        
        draw.ellipse([16, 16, 48, 48], fill=(30, 144, 255), outline=(255, 255, 255), width=3)
        
        for i in range(1, 4):
            draw.arc([16-i*4, 16-i*4, 48+i*4, 48+i*4], 0, 360, fill=(255, 255, 255), width=1)
        
        return image

    def log_action(self, message):
        """记录日志 - 修复编码问题"""
        if not self.enable_logging:
            return
            
        log_dir = r"C:\ZosIPLogs"
        if not os.path.exists(log_dir):
            os.makedirs(log_dir)
            
        log_file = os.path.join(log_dir, "zos_ip_client.log")
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        
        try:
            # 使用追加模式，指定UTF-8编码
            with open(log_file, 'a', encoding='utf-8') as f:
                f.write(f"{timestamp} - {message}\n")
        except Exception as e:
            # 如果UTF-8失败，尝试GBK
            try:
                with open(log_file, 'a', encoding='gbk') as f:
                    f.write(f"{timestamp} - {message}\n")
            except:
                pass

    def monitor_loop(self):
        """监控循环"""
        self.log_action("ZOS IP客户端 v2.0 启动成功 - 服务端监听已启用")
        
        self.check_and_update()
        
        while self.is_running:
            try:
                self.check_and_update()
            except Exception as e:
                self.log_action(f"监控异常: {str(e)}")
            
            time.sleep(self.check_interval)

    def check_and_update(self):
        """检查并更新IP"""
        if not self.auto_update:
            return False
            
        try:
            new_configured_ip = self.get_configured_ip()
            if new_configured_ip and new_configured_ip != self.current_ip:
                self.log_action(f"检测到IP变更: {self.current_ip} -> {new_configured_ip}")
                if self.update_static_ip_optimized(new_configured_ip, self.get_gateway(), self.get_subnet_mask(), self.get_dns_servers()):
                    self.configured_ip = new_configured_ip
                    return True
            elif new_configured_ip:
                self.configured_ip = new_configured_ip
            return False
        except Exception as e:
            self.log_action(f"检查更新失败: {str(e)}")
            return False

    def quit_app(self, icon=None, item=None):
        """退出应用程序 - 使用系统弹窗"""
        try: 
            root = tk.Tk()
            root.withdraw()
            root.attributes('-topmost', True)
            
            # 使用系统自带的询问字符串对话框
            password = simpledialog.askstring(
                "退出验证", 
                "请输入退出密码：", 
                show='*', 
                parent=root
            )
            
            root.destroy()
            
            if password == 'love00':
                # 密码正确，安全退出
                self.is_running = False
                if self.server_socket:
                    self.server_socket.close()
                self.log_action("ZOS IP客户端安全退出")
                self.icon.stop()
            else:
                # 密码错误
                if password is not None:  # 用户输入了密码但错误
                    # 使用系统错误对话框
                    messagebox.showerror("错误", "密码错误，退出失败！")
                # 如果用户点击取消，password为None，不显示错误消息
                
        except Exception as e:
            self.log_action(f"退出过程出错: {str(e)}")
            # 出错时强制退出
            self.is_running = False
            if hasattr(self, 'icon'):
                self.icon.stop()

    
    def create_input_dialog(self, title, prompt, default_text=""):
        """创建输入对话框"""
        def get_input():
            root = tk.Tk()
            root.withdraw()
            root.attributes('-topmost', True)
            self.set_window_icon(root)
            
            root.update_idletasks()
            width = 800
            height = 600
            x = (root.winfo_screenwidth() // 2) - (width // 2)
            y = (root.winfo_screenheight() // 2) - (height // 2)
            root.geometry(f'{width}x{height}+{x}+{y}')
            
            result = simpledialog.askstring(title, prompt, initialvalue=default_text, parent=root)
            root.destroy()
            return result
        
        return get_input()

    def show_system_status_menu(self, icon=None, item=None):
        self.show_system_status()

    def show_system_status(self):
        """显示系统状态"""
        status_text = f"""ZOS IP客户端 v2.0 - 系统状态

📋 基本信息：
   主机名: {self.hostname}
   MAC地址: {self.mac_address}
   当前IP: {self.current_ip}
   配置IP: {self.configured_ip or '未配置'}

🔧 服务状态：
   服务端口: {self.server_port}
   服务状态: {'运行中' if self.server_socket else '停止'}
   最后检查: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}

🌐 网络信息：
   适配器: {self.get_network_adapter()}
   网关: {self.get_gateway()}
   DNS: {', '.join(self.get_dns_servers())}

💡 使用提示：
   - 服务端监听已启用
   - 支持远程命令执行
   - 支持IP批量管理"""

        self.show_info_message("系统状态", status_text)

    def manual_set_ip(self, icon=None, item=None):
        """手动设置IP地址"""
        new_ip = self.create_input_dialog(
            "IP地址设置", 
            f"当前IP地址: {self.current_ip}\n\n请输入新的IP地址：",
            self.current_ip
        )
        
        if new_ip and new_ip != self.current_ip:
            if self.is_valid_ip(new_ip):
                gateway = self.get_gateway()
                subnet_mask = self.get_subnet_mask()
                dns_servers = self.get_dns_servers()
                
                self.process_network_change(
                    "手动IP更新确认",
                    "您即将手动更新网络配置",
                    self.current_ip,
                    new_ip,
                    gateway,
                    subnet_mask,
                    dns_servers,
                    'ip'
                )
            else:
                self.show_error_message("IP地址格式无效！\n\n请使用正确格式：192.168.1.100")

    def client_settings(self, icon=None, item=None):
        """客户端配置"""
        root = tk.Tk()
        root.title("ZOS IP客户端配置")
        root.geometry("500x400")
        root.resizable(False, False)
        self.set_window_icon(root)
        root.attributes('-topmost', True)
        
        root.update_idletasks()
        x = (root.winfo_screenwidth() // 2) - (500 // 2)
        y = (root.winfo_screenheight() // 2) - (400 // 2)
        root.geometry(f'500x400+{x}+{y}')
        
        tk.Label(root, text="ZOS服务器地址:", font=("Arial", 10)).pack(pady=5)
        server_var = tk.StringVar(value=self.zos_server)
        server_entry = tk.Entry(root, textvariable=server_var, width=30, font=("Arial", 10))
        server_entry.pack(pady=5)
        
        tk.Label(root, text="检查间隔(分钟):", font=("Arial", 10)).pack(pady=5)
        interval_var = tk.StringVar(value=str(self.check_interval // 60))
        interval_entry = tk.Entry(root, textvariable=interval_var, width=10, font=("Arial", 10))
        interval_entry.pack(pady=5)
        
        tk.Label(root, text="服务端口:", font=("Arial", 10)).pack(pady=5)
        port_var = tk.StringVar(value=str(self.server_port))
        port_entry = tk.Entry(root, textvariable=port_var, width=10, font=("Arial", 10))
        port_entry.pack(pady=5)
        
        tk.Label(root, text="退出密码:", font=("Arial", 10)).pack(pady=5)
        password_var = tk.StringVar()  # 不设置value参数，保持为空
        password_entry = tk.Entry(root, textvariable=password_var, width=20, font=("Arial", 10), show="*")
        password_entry.pack(pady=5)
        
        auto_update_var = tk.BooleanVar(value=self.auto_update)
        auto_update_cb = tk.Checkbutton(root, text="启用自动IP更新", variable=auto_update_var, font=("Arial", 10))
        auto_update_cb.pack(pady=5)
        
        logging_var = tk.BooleanVar(value=self.enable_logging)
        logging_cb = tk.Checkbutton(root, text="启用日志记录", variable=logging_var, font=("Arial", 10))
        logging_cb.pack(pady=5)
        
        def save_settings():
            try:
                self.zos_server = server_var.get()
                self.check_interval = int(interval_var.get()) * 60
                self.server_port = int(port_var.get())
                self.exit_password = password_var.get()
                self.auto_update = auto_update_var.get()
                self.enable_logging = logging_var.get()
                
                self.config.set('Client', 'zos_server', self.zos_server)
                self.config.set('Client', 'check_interval', str(self.check_interval))
                self.config.set('Client', 'server_port', str(self.server_port))
                self.config.set('Client', 'exit_password', self.exit_password)
                self.config.set('Client', 'auto_update', str(self.auto_update))
                self.config.set('Client', 'enable_logging', str(self.enable_logging))
                
                self.save_config()
                self.update_tray_tooltip()
                
                root.destroy()
                self.show_success_message("配置保存成功！\n\n部分设置需要重启客户端生效")
                
            except ValueError:
                self.show_error_message("请输入有效的数字")
            except Exception as e:
                self.show_error_message(f"保存配置失败: {str(e)}")
        
        button_frame = tk.Frame(root)
        button_frame.pack(pady=20)
        
        tk.Button(button_frame, text="保存", command=save_settings, width=10, font=("Arial", 10)).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text="取消", command=root.destroy, width=10, font=("Arial", 10)).pack(side=tk.LEFT, padx=10)
        
        root.mainloop()

    def show_logs(self, icon=None, item=None):
        """显示日志 - 简化版编码处理"""
        def show_logs_window():
            log_file = r"C:\ZosIPLogs\zos_ip_client.log"
            if not os.path.exists(log_file):
                def show_no_logs():
                    root = tk.Tk()
                    root.withdraw()
                    messagebox.showinfo("日志", "暂无日志记录", parent=root)
                    root.destroy()
                threading.Thread(target=show_no_logs, daemon=True).start()
                return
            
            try:
                # 直接使用UTF-8读取，如果失败则使用系统默认编码
                try:
                    with open(log_file, 'r', encoding='utf-8') as f:
                        log_content = f.read()
                except UnicodeDecodeError:
                    # 如果UTF-8失败，使用系统默认编码（通常是GBK）
                    with open(log_file, 'r', encoding='gbk') as f:
                        log_content = f.read()
                
                root = tk.Tk()
                root.title("ZOS IP客户端日志")
                root.geometry("800x600")
                self.set_window_icon(root)
                root.attributes('-topmost', True)
                
                # ... 其余代码保持不变 ...
                
                root.update_idletasks()
                x = (root.winfo_screenwidth() // 2) - (800 // 2)
                y = (root.winfo_screenheight() // 2) - (600 // 2)
                root.geometry(f'800x600+{x}+{y}')
                
                text_area = scrolledtext.ScrolledText(root, wrap=tk.WORD, font=("Consolas", 9))
                text_area.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
                text_area.insert(tk.END, log_content)
                text_area.config(state=tk.DISABLED)
                
                button_frame = tk.Frame(root)
                button_frame.pack(pady=10)
                
                tk.Button(button_frame, text="刷新", command=lambda: self.refresh_logs(text_area), font=("Arial", 9)).pack(side=tk.LEFT, padx=5)
                tk.Button(button_frame, text="清空日志", command=lambda: self.clear_logs(text_area), font=("Arial", 9)).pack(side=tk.LEFT, padx=5)
                tk.Button(button_frame, text="关闭", command=root.destroy, font=("Arial", 9)).pack(side=tk.LEFT, padx=5)
                
                root.mainloop()
                
            except Exception as error:
                error_msg = str(error)
                def show_error():
                    error_root = tk.Tk()
                    error_root.withdraw()
                    messagebox.showerror("错误", f"读取日志失败: {error_msg}", parent=error_root)
                    error_root.destroy()
                threading.Thread(target=show_error, daemon=True).start()
        
        log_thread = threading.Thread(target=show_logs_window, daemon=True)
        log_thread.start()

    def refresh_logs(self, text_area):
        """刷新日志显示"""
        log_file = r"C:\ZosIPLogs\zos_ip_client.log"
        try:
            # 使用相同的多种编码方式
            encodings = ['utf-8', 'gbk', 'gb2312', 'latin-1']
            log_content = ""
            
            for encoding in encodings:
                try:
                    with open(log_file, 'r', encoding=encoding) as f:
                        log_content = f.read()
                    break
                except UnicodeDecodeError:
                    continue
            
            if not log_content:
                with open(log_file, 'rb') as f:
                    raw_content = f.read()
                    log_content = raw_content.decode('utf-8', errors='ignore')
            
            text_area.config(state=tk.NORMAL)
            text_area.delete(1.0, tk.END)
            text_area.insert(tk.END, log_content)
            text_area.config(state=tk.DISABLED)
            text_area.see(tk.END)
        except Exception as e:
            self.show_error_message(f"刷新日志失败: {str(e)}")

    def clear_logs(self, text_area):
        """清空日志"""
        if self.show_confirm_dialog("清空日志", "确定要清空所有日志记录吗？"):
            log_file = r"C:\ZosIPLogs\zos_ip_client.log"
            try:
                with open(log_file, 'w', encoding='utf-8') as f:
                    f.write("")
                
                text_area.config(state=tk.NORMAL)
                text_area.delete(1.0, tk.END)
                text_area.config(state=tk.DISABLED)
                self.show_success_message("日志已清空")
            except Exception as e:
                self.show_error_message(f"清空日志失败: {str(e)}")

    def notify_task_completion(self, task_type, success, message):
        """通知服务器任务完成状态"""
        try:
            self.log_action(f"任务完成通知: {task_type} - {'成功' if success else '失败'} - {message}")
        except Exception as e:
            self.log_action(f"通知任务状态失败: {str(e)}")

    def task_monitor_loop(self):
        """任务监控循环"""
        self.log_action("任务监控启动")
        
        while self.is_running:
            try:
                pass
            except Exception as e:
                self.log_action(f"任务监控异常: {str(e)}")
            
            time.sleep(self.task_check_interval)

    def get_detailed_system_info(self):
        """获取详细系统信息"""
        try:
            cpu_info = {
                'physical_cores': psutil.cpu_count(logical=False),
                'total_cores': psutil.cpu_count(logical=True),
                'max_frequency': psutil.cpu_freq().max if psutil.cpu_freq() else '未知',
                'usage_percent': psutil.cpu_percent(interval=1)
            }
            
            memory = psutil.virtual_memory()
            memory_info = {
                'total': f"{memory.total // (1024**3)} GB",
                'available': f"{memory.available // (1024**3)} GB",
                'used': f"{memory.used // (1024**3)} GB",
                'percent': memory.percent
            }
            
            disk = psutil.disk_usage('C:\\')
            disk_info = {
                'total': f"{disk.total // (1024**3)} GB",
                'used': f"{disk.used // (1024**3)} GB",
                'free': f"{disk.free // (1024**3)} GB",
                'percent': disk.percent
            }
            
            network_info = {
                'adapter': self.get_network_adapter(),
                'ip_address': self.current_ip,
                'mac_address': self.mac_address,
                'subnet_mask': self.get_subnet_mask(),
                'gateway': self.get_gateway(),
                'dns_servers': self.get_dns_servers()
            }
            
            system_info = {
                'hostname': self.hostname,
                'os_version': f"Windows {os.environ.get('OS', 'Unknown')}",
                'architecture': os.environ.get('PROCESSOR_ARCHITECTURE', 'Unknown'),
                'boot_time': datetime.fromtimestamp(psutil.boot_time()).strftime('%Y-%m-%d %H:%M:%S')
            }
            
            return {
                'cpu': cpu_info,
                'memory': memory_info,
                'disk': disk_info,
                'network': network_info,
                'system': system_info
            }
            
        except Exception as e:
            self.log_action(f"获取系统信息失败: {str(e)}")
            return {}

    def update_computer_name(self, new_hostname):
        """修改计算机名"""
        try:
            cmd = f"Rename-Computer -NewName '{new_hostname}' -Force"
            result = subprocess.run(
                ["powershell", "-Command", cmd],
                capture_output=True, text=True, timeout=30,
                creationflags=subprocess.CREATE_NO_WINDOW
            )
            
            if result.returncode == 0:
                self.log_action(f"计算机名修改成功: {self.hostname} -> {new_hostname}")
                self.hostname = new_hostname
                self.update_tray_tooltip()
                return True
            else:
                error_msg = f"修改计算机名失败: {result.stderr}"
                self.log_action(error_msg)
                return False
                
        except subprocess.TimeoutExpired:
            error_msg = "修改计算机名超时"
            self.log_action(error_msg)
            return False
        except Exception as e:
            error_msg = f"修改计算机名异常: {str(e)}"
            self.log_action(error_msg)
            return False

    def update_static_ip_optimized(self, new_ip, gateway="", subnet_mask="", dns_servers=None):
        """优化版IP地址更新方法"""
        try:
            adapter = self.get_network_adapter_optimized()
            if not adapter:
                self.log_action("无法获取网络适配器")
                return False

            self.log_action(f"开始更新IP配置 - 适配器: {adapter}, 新IP: {new_ip}, 网关: {gateway}")

            try:
                cmd1 = f'netsh interface ip set address "{adapter}" static {new_ip} {subnet_mask} {gateway} 1'
                result1 = subprocess.run(cmd1, shell=True, capture_output=True, text=True, timeout=30,
                                       creationflags=subprocess.CREATE_NO_WINDOW)
                
                if result1.returncode != 0:
                    self.log_action(f"netsh设置IP失败: {result1.stderr}")
                    raise Exception(f"设置IP失败: {result1.stderr}")

                if dns_servers:
                    cmd_clear_dns = f'netsh interface ip set dns "{adapter}" static addr=none'
                    subprocess.run(cmd_clear_dns, shell=True, capture_output=True, timeout=10,
                                 creationflags=subprocess.CREATE_NO_WINDOW)
                    
                    if len(dns_servers) > 0:
                        cmd_dns1 = f'netsh interface ip set dns "{adapter}" static {dns_servers[0]} primary'
                        subprocess.run(cmd_dns1, shell=True, capture_output=True, timeout=10,
                                     creationflags=subprocess.CREATE_NO_WINDOW)
                    
                    if len(dns_servers) > 1:
                        cmd_dns2 = f'netsh interface ip add dns "{adapter}" {dns_servers[1]} index=2'
                        subprocess.run(cmd_dns2, shell=True, capture_output=True, timeout=10,
                                     creationflags=subprocess.CREATE_NO_WINDOW)

                time.sleep(3)
                new_current_ip = self.get_current_ip()
                
                if new_current_ip == new_ip:
                    old_ip = self.current_ip
                    self.current_ip = new_ip
                    self.log_action(f"IP地址更新成功: {old_ip} -> {new_ip}")
                    self.update_tray_tooltip()
                    return True
                else:
                    self.log_action(f"IP验证失败: 期望 {new_ip}, 实际 {new_current_ip}")
                    # 即使验证失败，也更新当前IP变量
                    self.current_ip = new_ip
                    self.update_tray_tooltip()
                    return False

            except Exception as e:
                self.log_action(f"netsh方法失败: {str(e)}")
                return self.update_static_ip_powershell(new_ip, gateway, subnet_mask, dns_servers, adapter)

        except Exception as e:
            error_msg = f"IP地址更新失败: {str(e)}"
            self.log_action(error_msg)
            return False

    def update_dns_servers_only(self, dns_servers):
        """仅更新DNS服务器"""
        try:
            adapter = self.get_network_adapter_optimized()
            if not adapter:
                self.log_action("无法获取网络适配器")
                return False

            self.log_action(f"开始更新DNS配置 - 适配器: {adapter}, DNS: {dns_servers}")

            # 使用PowerShell命令更新DNS
            dns_servers_str = ','.join([f"'{dns}'" for dns in dns_servers])
            
            # 先清除现有DNS设置
            clear_cmd = f"Set-DnsClientServerAddress -InterfaceAlias '{adapter}' -ResetServerAddresses"
            result_clear = subprocess.run(
                ["powershell", "-Command", clear_cmd], 
                capture_output=True, 
                text=True, 
                timeout=15,
                creationflags=subprocess.CREATE_NO_WINDOW
            )
            
            if result_clear.returncode != 0:
                self.log_action(f"清除DNS设置失败: {result_clear.stderr}")
                # 继续尝试设置新的DNS，不清除可能也能工作
            
            # 设置新的DNS服务器
            set_dns_cmd = f"Set-DnsClientServerAddress -InterfaceAlias '{adapter}' -ServerAddresses @({dns_servers_str})"
            result_set = subprocess.run(
                ["powershell", "-Command", set_dns_cmd], 
                capture_output=True, 
                text=True, 
                timeout=15,
                creationflags=subprocess.CREATE_NO_WINDOW
            )
            
            if result_set.returncode == 0:
                self.log_action(f"DNS配置更新成功: {dns_servers}")
                
                # 验证DNS设置是否生效
                time.sleep(2)
                current_dns = self.get_dns_servers()
                self.log_action(f"当前DNS设置: {current_dns}")
                
                return True
            else:
                error_msg = f"DNS配置更新失败: {result_set.stderr}"
                self.log_action(error_msg)
                return False
                
        except Exception as e:
            error_msg = f"DNS配置更新异常: {str(e)}"
            self.log_action(error_msg)
            return False

    def update_static_ip_powershell(self, new_ip, gateway, subnet_mask, dns_servers, adapter):
        """使用PowerShell更新IP地址"""
        try:
            prefix_length = self.subnet_mask_to_prefix_length(subnet_mask)
            
            try:
                remove_cmd = f"Remove-NetIPAddress -InterfaceAlias '{adapter}' -Confirm:$false"
                subprocess.run(["powershell", "-Command", remove_cmd], capture_output=True, timeout=15,
                             creationflags=subprocess.CREATE_NO_WINDOW)
            except:
                pass

            set_ip_cmd = f"New-NetIPAddress -InterfaceAlias '{adapter}' -IPAddress {new_ip} -PrefixLength {prefix_length} -DefaultGateway {gateway}"
            result = subprocess.run(["powershell", "-Command", set_ip_cmd], capture_output=True, text=True, timeout=30,
                                  creationflags=subprocess.CREATE_NO_WINDOW)
            
            if result.returncode != 0:
                self.log_action(f"PowerShell设置IP失败: {result.stderr}")
                return False

            if dns_servers:
                dns_servers_str = ','.join([f"'{dns}'" for dns in dns_servers])
                set_dns_cmd = f"Set-DnsClientServerAddress -InterfaceAlias '{adapter}' -ServerAddresses @({dns_servers_str})"
                subprocess.run(["powershell", "-Command", set_dns_cmd], capture_output=True, timeout=15,
                             creationflags=subprocess.CREATE_NO_WINDOW)

            time.sleep(3)
            new_current_ip = self.get_current_ip()
            
            if new_current_ip == new_ip:
                old_ip = self.current_ip
                self.current_ip = new_ip
                self.log_action(f"PowerShell方法IP更新成功: {old_ip} -> {new_ip}")
                self.update_tray_tooltip()
                return True
            else:
                self.log_action(f"PowerShell方法IP验证失败: 期望 {new_ip}, 实际 {new_current_ip}")
                # 即使验证失败，也更新当前IP变量
                self.current_ip = new_ip
                self.update_tray_tooltip()
                return False

        except Exception as e:
            self.log_action(f"PowerShell方法也失败: {str(e)}")
            return False

    def get_network_adapter_optimized(self):
        """优化获取网络适配器的方法"""
        try:
            if self.current_ip != "未知":
                cmd = f"Get-NetIPAddress -IPAddress {self.current_ip} | Select-Object -ExpandProperty InterfaceAlias"
                result = subprocess.run(["powershell", "-Command", cmd], capture_output=True, text=True, timeout=10,
                                      creationflags=subprocess.CREATE_NO_WINDOW)
                adapter = result.stdout.strip()
                if adapter:
                    return adapter

            cmd = """Get-NetAdapter | Where-Object { 
    $_.Status -eq 'Up' -and 
    $_.InterfaceDescription -notlike '*Virtual*' -and 
    $_.InterfaceDescription -notlike '*VPN*' -and
    $_.Name -notlike '*Virtual*' -and
    $_.Name -notlike '*VPN*'
} | Select-Object -First 1 | Select-Object -ExpandProperty Name"""
            
            result = subprocess.run(["powershell", "-Command", cmd], capture_output=True, text=True, timeout=10,
                                  creationflags=subprocess.CREATE_NO_WINDOW)
            adapter = result.stdout.strip()
            if adapter:
                return adapter

            cmd = "Get-NetIPAddress -AddressFamily IPv4 | Where-Object {$_.IPAddress -ne '127.0.0.1'} | Select-Object -First 1 | Select-Object -ExpandProperty InterfaceAlias"
            result = subprocess.run(["powershell", "-Command", cmd], capture_output=True, text=True, timeout=10,
                                  creationflags=subprocess.CREATE_NO_WINDOW)
            adapter = result.stdout.strip()
            
            return adapter or "以太网"

        except Exception as e:
            self.log_action(f"获取网络适配器失败: {str(e)}")
            return "以太网"

    def update_static_ip(self, new_ip, gateway="", subnet_mask="", dns_servers=None):
        """更新静态IP - 兼容旧版本"""
        return self.update_static_ip_optimized(new_ip, gateway, subnet_mask, dns_servers)

    def get_network_adapter(self):
        """获取网络适配器 - 兼容旧版本"""
        return self.get_network_adapter_optimized()

    def subnet_mask_to_prefix_length(self, subnet_mask):
        """将子网掩码转换为前缀长度"""
        try:
            common_masks = {
                '255.255.255.0': 24,
                '255.255.0.0': 16,
                '255.0.0.0': 8,
                '255.255.255.128': 25,
                '255.255.255.192': 26,
                '255.255.255.224': 27,
                '255.255.255.240': 28,
                '255.255.255.248': 29,
                '255.255.255.252': 30
            }
            
            if subnet_mask in common_masks:
                return common_masks[subnet_mask]
            
            return 24
        except:
            return 24

    def get_subnet_mask(self):
        """获取子网掩码"""
        try:
            cmd = "Get-NetIPAddress -AddressFamily IPv4 | Where-Object {$_.IPAddress -eq '" + self.current_ip + "'} | Select-Object -ExpandProperty PrefixLength"
            result = subprocess.run(
                ["powershell", "-Command", cmd],
                capture_output=True, text=True, timeout=5,
                creationflags=subprocess.CREATE_NO_WINDOW
            )
            prefix = result.stdout.strip()
            if prefix:
                prefix = int(prefix)
                mask = (0xffffffff << (32 - prefix)) & 0xffffffff
                return ".".join([str((mask >> (8 * i)) & 0xff) for i in range(3, -1, -1)])
            return "255.255.255.0"
        except:
            return "255.255.255.0"

    def get_mac_address(self):
        """获取MAC地址"""
        try:
            for interface, addrs in psutil.net_if_addrs().items():
                for addr in addrs:
                    if addr.family == psutil.AF_LINK and interface != 'Loopback Pseudo-Interface 1':
                        return addr.address.replace('-', ':')
            return "unknown"
        except:
            return "unknown"

    def get_current_ip(self):
        """获取当前IP地址"""
        try:
            try:
                s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
                s.connect(("8.8.8.8", 80))
                ip = s.getsockname()[0]
                s.close()
                if ip and ip != '127.0.0.1':
                    return ip
            except:
                pass
            
            cmd = "Get-NetIPAddress -AddressFamily IPv4 | Where-Object {$_.InterfaceAlias -notlike '*Loopback*' -and $_.IPAddress -notlike '169.254.*'} | Select-Object -First 1 IPAddress"
            result = subprocess.run(
                ["powershell", "-Command", cmd],
                capture_output=True, text=True, timeout=10,
                creationflags=subprocess.CREATE_NO_WINDOW
            )
            lines = result.stdout.strip().split('\n')
            for line in lines:
                line = line.strip()
                if '.' in line and not line.startswith('IPAddress'):
                    return line
            return "未知"
        except:
            return "未知"

    def get_configured_ip(self):
        """从ZOS服务器获取配置的IP"""
        try:
            url = f"http://{self.zos_server}/zos/ipaddress/index.php"
            params = {"mac": self.mac_address}
            
            response = requests.get(url, params=params, timeout=10, verify=False)
            response.raise_for_status()
            
            ip = response.text.strip()
            if self.is_valid_ip(ip):
                return ip
            return None
        except Exception as e:
            self.log_action(f"获取配置IP失败: {str(e)}")
            return None

    def is_valid_ip(self, ip):
        """验证IP格式"""
        try:
            parts = ip.split('.')
            if len(parts) != 4:
                return False
            for part in parts:
                if not part.isdigit() or not 0 <= int(part) <= 255:
                    return False
            return True
        except:
            return False

    def get_gateway(self):
        """获取网关"""
        try:
            cmd = "Get-NetRoute -DestinationPrefix '0.0.0.0/0' | Where-Object {$_.NextHop -ne '0.0.0.0'} | Select-Object -First 1 | Select-Object -ExpandProperty NextHop"
            result = subprocess.run(
                ["powershell", "-Command", cmd],
                capture_output=True, text=True, timeout=10,
                creationflags=subprocess.CREATE_NO_WINDOW
            )
            gateway = result.stdout.strip()
            if gateway and self.is_valid_ip(gateway):
                return gateway
            
            if self.current_ip != "未知" and self.is_valid_ip(self.current_ip):
                parts = self.current_ip.split('.')
                return f"{parts[0]}.{parts[1]}.{parts[2]}.1"
            
            return "192.168.1.1"
        except:
            return "192.168.1.1"

    def get_dns_servers(self):
        """获取DNS服务器"""
        try:
            cmd = "Get-DnsClientServerAddress -AddressFamily IPv4 | Where-Object {$_.InterfaceAlias -notlike '*Loopback*'} | Select-Object -First 1 | Select-Object -ExpandProperty ServerAddresses"
            result = subprocess.run(
                ["powershell", "-Command", cmd],
                capture_output=True, text=True, timeout=10,
                creationflags=subprocess.CREATE_NO_WINDOW
            )
            dns_servers = result.stdout.strip().split('\n')
            return [dns.strip() for dns in dns_servers if dns.strip() and self.is_valid_ip(dns.strip())]
        except:
            return ['8.8.8.8', '114.114.114.114']

    def show_received_files(self, icon=None, item=None):
        """显示接收文件列表"""
        try:
            root = tk.Tk()
            root.title("接收文件列表 - ZOS IP客户端")
            root.geometry("800x600")
            self.set_window_icon(root)
            root.attributes('-topmost', True)
            
            # 居中显示
            root.update_idletasks()
            x = (root.winfo_screenwidth() // 2) - (800 // 2)
            y = (root.winfo_screenheight() // 2) - (600 // 2)
            root.geometry(f'800x600+{x}+{y}')
            
            # 创建主框架
            main_frame = ttk.Frame(root)
            main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
            
            # 标题和统计
            header_frame = ttk.Frame(main_frame)
            header_frame.pack(fill=tk.X, pady=(0, 10))
            
            ttk.Label(header_frame, text="📁 接收文件列表", font=("Arial", 12, "bold")).pack(anchor=tk.W)
            
            # 文件列表框架
            list_frame = ttk.LabelFrame(main_frame, text="文件列表")
            list_frame.pack(fill=tk.BOTH, expand=True)
            
            # 创建表格
            columns = ('filename', 'size', 'modified', 'path')
            file_tree = ttk.Treeview(list_frame, columns=columns, show='headings', height=15)
            
            file_tree.heading('filename', text='文件名')
            file_tree.heading('size', text='大小')
            file_tree.heading('modified', text='修改时间')
            file_tree.heading('path', text='路径')
            
            file_tree.column('filename', width=200)
            file_tree.column('size', width=100)
            file_tree.column('modified', width=150)
            file_tree.column('path', width=300)
            
            # 添加滚动条
            scrollbar = ttk.Scrollbar(list_frame, orient=tk.VERTICAL, command=file_tree.yview)
            file_tree.configure(yscrollcommand=scrollbar.set)
            
            file_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
            scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
            
            # 按钮框架
            button_frame = ttk.Frame(main_frame)
            button_frame.pack(fill=tk.X, pady=(10, 0))
            
            ttk.Button(button_frame, text="刷新", 
                      command=lambda: self.refresh_file_list(file_tree)).pack(side=tk.LEFT, padx=5)
            ttk.Button(button_frame, text="打开文件", 
                      command=lambda: self.open_selected_file(file_tree)).pack(side=tk.LEFT, padx=5)
            ttk.Button(button_frame, text="打开目录", 
                      command=lambda: self.open_file_directory()).pack(side=tk.LEFT, padx=5)
            ttk.Button(button_frame, text="删除文件", 
                      command=lambda: self.delete_selected_file(file_tree)).pack(side=tk.LEFT, padx=5)
            ttk.Button(button_frame, text="关闭", 
                      command=root.destroy).pack(side=tk.RIGHT, padx=5)
            
            # 绑定双击事件
            file_tree.bind('<Double-1>', lambda e: self.open_selected_file(file_tree))
            
            # 初始加载文件列表
            self.refresh_file_list(file_tree)
            
            root.mainloop()
            
        except Exception as e:
            self.show_error_message(f"打开文件列表失败: {str(e)}")

    def refresh_file_list(self, file_tree):
        """刷新文件列表"""
        try:
            # 清空现有列表
            for item in file_tree.get_children():
                file_tree.delete(item)
        
            # 获取文件列表
            if not os.path.exists(self.received_files_dir):
                os.makedirs(self.received_files_dir)
                return
            
            files = os.listdir(self.received_files_dir)
            
            for filename in files:
                filepath = os.path.join(self.received_files_dir, filename)
                if os.path.isfile(filepath):
                    file_stat = os.stat(filepath)
                    
                    # 格式化文件大小
                    size = file_stat.st_size
                    if size < 1024:
                        size_str = f"{size} B"
                    elif size < 1024 * 1024:
                        size_str = f"{size/1024:.1f} KB"
                    else:
                        size_str = f"{size/(1024*1024):.1f} MB"
                    
                    # 格式化时间
                    mtime = datetime.fromtimestamp(file_stat.st_mtime)
                    time_str = mtime.strftime("%Y-%m-%d %H:%M:%S")
                    
                    file_tree.insert('', 'end', values=(
                        filename, size_str, time_str, filepath
                    ))
                    
        except Exception as e:
            self.show_error_message(f"刷新文件列表失败: {str(e)}")

    def open_selected_file(self, file_tree):
        """打开选中的文件"""
        try:
            selection = file_tree.selection()
            if not selection:
                self.show_info_message("提示", "请先选择一个文件")
                return
            
            item = selection[0]
            values = file_tree.item(item, 'values')
            filepath = values[3]  # 路径在第四列
            
            if os.path.exists(filepath):
                os.startfile(filepath)
            else:
                self.show_error_message(f"文件不存在: {filepath}")
                
        except Exception as e:
            self.show_error_message(f"打开文件失败: {str(e)}")

    def open_file_directory(self):
        """打开文件目录"""
        try:
            if os.path.exists(self.received_files_dir):
                os.startfile(self.received_files_dir)
            else:
                os.makedirs(self.received_files_dir)
                os.startfile(self.received_files_dir)
        except Exception as e:
            self.show_error_message(f"打开目录失败: {str(e)}")

    def delete_selected_file(self, file_tree):
        """删除选中的文件"""
        try:
            selection = file_tree.selection()
            if not selection:
                self.show_info_message("提示", "请先选择一个文件")
                return
            
            item = selection[0]
            values = file_tree.item(item, 'values')
            filename = values[0]
            filepath = values[3]
            
            if messagebox.askyesno("确认删除", f"确定要删除文件 {filename} 吗？"):
                os.remove(filepath)
                file_tree.delete(item)
                self.show_success_message(f"文件 {filename} 已删除")
                
        except Exception as e:
            self.show_error_message(f"删除文件失败: {str(e)}")

    def process_network_change(self, title, message, old_ip, new_ip, gateway, subnet_mask, dns_servers, change_type):
        """处理网络配置变更"""
        success = self.show_countdown_dialog_for_network_change(
            title,
            message,
            old_ip,
            new_ip,
            gateway,
            subnet_mask,
            dns_servers,
            timeout=15,
            change_type=change_type
        )
        
        if success:
            if change_type == 'both':
                self.show_success_message(f"网络配置已更新: {old_ip} -> {new_ip}, DNS: {dns_servers}")
            elif change_type == 'ip':
                self.show_success_message(f"IP地址已更新: {old_ip} -> {new_ip}")
            else:
                self.show_success_message(f"DNS配置已更新: {dns_servers}")
        else:
            self.show_error_message("网络配置更新已取消")

    def run(self):
        """运行应用程序"""
        try:
            self.icon.run()
        except Exception as e:
            self.show_error_message(f"应用程序启动失败: {str(e)}")

if __name__ == "__main__":
    log_dir = r"C:\ZosIPLogs"
    if not os.path.exists(log_dir):
        os.makedirs(log_dir)
    
    app = ZosTrayClient()
    app.run()
